package com.moss.cloud.common.core.utils;

import lombok.extern.slf4j.Slf4j;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;


/**
 * 时间处理工具类
 * @data 2019/07/12
 * @author 瑾年
 * @version 1.0.0
 */
@Slf4j
public class DateUtil {
    /**
     * 英文全称 如：2019-01-01
     */
    public static final String YMD = "yyyy-MM-dd";
    /**
     * 英文全称 如：2019-01-01 23:15:06
     */
    public static final String FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";
    /**
     * 中文简写 如：2019年01月01日
     */
    public static final String FORMAT_SHORT_CN = "yyyy年MM月dd日";
    /**
     * 中文全称 如：2019年01月01日 23时15分06秒
     */
    public static final String FORMAT_LONG_CN = "yyyy年MM月dd日  HH时mm分ss秒";
    /**
     * 精确到毫秒的完整时间 如：yyyy-MM-dd HH:mm:ss.S
     */
    public static final String FORMAT_FULL = "yyyy-MM-dd HH:mm:ss.S";
    /**
     * 英文简写如：2019
     */
    public static final String FORMAT_Y = "yyyy";
    /**
     * 英文简写如：2010-04
     */
    public static final String FORMAT_YM = "yyyy-MM";

    public static final String FORMAT_NO_SLIP = "yyyyMMddHHmmss";

    /**
     * 将LocalDateTime转为自定义的时间格式的字符串
     * @param localDateTime
     * @param format
     * @return
     */
    public static String getDateTimeAsString(LocalDateTime localDateTime, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(formatter);
    }

    /**
     * 将long类型的timestamp转为LocalDateTime
     * @param timestamp
     * @return
     */
    public static LocalDateTime getDateTimeOfTimestamp(long timestamp) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * 将LocalDateTime转为long类型的timestamp
     * @param localDateTime
     * @return
     */
    public static long getTimestampOfDateTime(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return instant.toEpochMilli();
    }

    /**
     * 将某时间字符串转为自定义时间格式的LocalDateTime
     * @param time
     * @param format
     * @return
     */
    public static LocalDateTime parseStringToDateTime(String time, String format) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(time, df);
    }

    /**
     * 时间戳转特定的时间格式
     * @param timestamp
     * @param format
     * @return
     */
    public static String getDateTimeOfTimestamp(long timestamp, String format) {
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
        return dateTimeFormatter.format(localDateTime);
    }

    /**
     * 使用LocalDateTime计算两个时间的差
     * @param val1 时间1
     * @param val2 时间2 大于 时间1
     * @param timeType 计算类型，1表示计算相差天数，2表示计算相差小时，3表示计算相差分钟数，4表示计算相差秒数
     * @return
     */
    public static Long getLocalDataTimes(LocalDateTime val1,LocalDateTime val2,int timeType){
        Duration duration = Duration.between(val1,val2);
        Long times = 0L;
        if(timeType==1){
            //1表示计算相差天数
            times = duration.toDays();
        }else if(timeType==2){
            //2表示计算相差小时
            times = duration.toHours();
        }else if(timeType==3){
            //3表示计算相差分钟数
            times = duration.toMillis();
        }else if(timeType==4){
            //4表示计算相差秒数
            times = duration.toMinutes();
        }
        return times;
    }

    /**
     * 根据当前日期获取本周星期一，之后星期数天数获得，
     * 星期二+1、星期三+2、星期四+3、星期五+4、星期六+5、星期天+6
     * @author jinnian
     * @return
     */
    public static String getMonday() throws ParseException {
        SimpleDateFormat sdf=new SimpleDateFormat(YMD); //设置时间格式
        Calendar cal = Calendar.getInstance();
        Date time=sdf.parse(getNow());
        cal.setTime(time);
        //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        if(1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        cal.setFirstDayOfWeek(Calendar.MONDAY);//设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int day = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek()-day);//根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        return sdf.format(cal.getTime());
    }
    /**
     * 根据预设格式返回当前日期
     * @return
     */
    public static String getNow() {
        return format(new Date());
    }

    /**
     * 根据用户格式返回当前日期
     *
     * @param format
     * @return
     */
    public static String getNow(String format) {
        return format(new Date(), format);
    }
    /**
     * 使用预设格式格式化日期
     * @param date
     * @return
     */
    public static String format(Date date) {
        return format(date, FORMAT_LONG);
    }
    /**
     * 使用用户格式格式化日期
     * @param date 日期
     * @param pattern 日期格式
     * @return
     */
    public static String format(Date date, String pattern) {
        String returnValue = "";
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            returnValue = df.format(date);
        }
        return (returnValue);
    }
    /**
     * 使用用户格式提取字符串日期
     * @param strDate 日期字符串
     * @param pattern 日期格式
     * @return
     */
    public static Date parse(String strDate, String pattern) {
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        try {
            return df.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 在日期上增加年数
     * @param date 日期
     * @param n 要增加的年数
     * @return
     */
    public static Date addYear(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.YEAR, n);
        return cal.getTime();
    }
    /**
     * 在日期上增加数个整月
     * @param date 日期
     * @param n 要增加的月数
     * @return
     */
    public static Date addMonth(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, n);
        return cal.getTime();
    }
    /**
     * 在日期上增加天数
     * @param date 日期
     * @param n 要增加的天数
     * @return
     */
    public static Date addDay(Date date, int n) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, n);
        return cal.getTime();
    }
    /**
     * @Description: 计算两个时间相差天数
     * @Param: [startTime, endTime]
     * @return: int
     */
    public static int getBetweenDays(LocalDateTime startTime, LocalDateTime endTime){
        // 开始日
        LocalDate startDate = startTime.toLocalDate();
        // 结束日
        LocalDate endDate = endTime.toLocalDate();
        // 天数
        return  (int)(endDate.toEpochDay()-startDate.toEpochDay());
    }
    /**
     * 获取当前时间戳
     * 精确到毫秒
     */
    public static String getTimeString() {
        SimpleDateFormat df = new SimpleDateFormat(FORMAT_FULL);
        Calendar calendar = Calendar.getInstance();
        return df.format(calendar.getTime());
    }
    /**
     * date转String yyyy-MM-dd
     * @param dateDate
     * @return
     */
    public static String dateToStr(Date dateDate) {
        SimpleDateFormat formatter = new SimpleDateFormat(YMD);
        String dateString = formatter.format(dateDate);
        return dateString;
    }

    /**
     * 获取指定时间的前n天
     * @param date
     * @return
     */
    public static  String beforeYesterday(String date,int toDay){
        String beforeYesterday = getNow();
        try{
            //解析指定Date
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(YMD, Locale.getDefault());
            Date parseDate = simpleDateFormat.parse(date);
            //设置Calendar
            Calendar calendar = GregorianCalendar.getInstance();
            calendar.setTime(parseDate);
            //核心代码，回滚到前一天。
            back(calendar,toDay);
            //转换格式
            beforeYesterday = simpleDateFormat.format(calendar.getTime());
        }catch (Exception e){
            log.error("时间转换异常:{}",e.getMessage());
        }
        return beforeYesterday;
    }

    /**
     * 使用set()方法回滚 前几天
     * @param calendar
     */
    private static void back(Calendar calendar,int toDay) {
        int day = calendar.get(Calendar.DATE);
        calendar.set(Calendar.DATE, day - toDay);
    }

    /**
     * 获取当前年的12个月份
     * @return yearMonths
     */
    public static String[] yearMonths(){
        String year = getNow(FORMAT_Y);
        String[] yearMonths =new String[12];
        for(int i = 0; i < 12; i++){
            String yearMonth = year;
            if(i+1>=10){
                yearMonth = year+"-"+(i+1);
            }else {
                yearMonth = year+"-0"+(i+1);
            }
            yearMonths[i] = yearMonth;
        }
        return yearMonths;
    }

    /**
     * 计算某年某月的开始时间
     * @param year
     * @param month
     * @return
     */
    public static String getBeginTime(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate localDate = yearMonth.atDay(1);
        LocalDateTime startOfDay = localDate.atStartOfDay();
        ZonedDateTime zonedDateTime = startOfDay.atZone(ZoneId.of("Asia/Shanghai"));
        return dateToStr(Date.from(zonedDateTime.toInstant()));
    }

    /**
     * 计算某年某月的结束时间
     * @param year
     * @param month
     * @return
     */
    public static String getEndTime(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate endOfMonth = yearMonth.atEndOfMonth();
        LocalDateTime localDateTime = endOfMonth.atTime(23, 59, 59, 999);
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
        return dateToStr(Date.from(zonedDateTime.toInstant()));
    }

    /**
     * 上月开始时间
     * @return
     */
    public static String lastStarTime(){
        //获取当前年月
        String nowYm = getNow(FORMAT_YM);
        //本月DATE类型
        Date nowDate = parse(nowYm,FORMAT_YM);
        //上个月DATE类型
        Date lastDate = addMonth(nowDate,-1);
        //上月String类型
        String lastDateStr = format(lastDate,FORMAT_YM);
        //上月年份
        int lastY = Integer.parseInt(lastDateStr.split("-")[0]);
        //上月月份
        int lastM = Integer.parseInt(lastDateStr.split("-")[1]);
        //上个月开始时间
        String lastStartTime = getBeginTime(lastY,lastM);
        return lastStartTime;
    }
    /**
     * 上月结束时间
     */
    public static String lastEndTime(){
        //获取当前年月
        String nowYm = getNow(FORMAT_YM);
        //本月DATE类型
        Date nowDate = parse(nowYm,FORMAT_YM);
        //上个月DATE类型
        Date lastDate = addMonth(nowDate,-1);
        //上月String类型
        String lastDateStr = format(lastDate,FORMAT_YM);
        //上月年份
        int lastY = Integer.parseInt(lastDateStr.split("-")[0]);
        //上月月份
        int lastM = Integer.parseInt(lastDateStr.split("-")[1]);
        //上个月开始时间
        String lastEndTime = getEndTime(lastY,lastM);
        return lastEndTime;
    }

    /**
     * 本月开始时间
     * @return
     */
    public static String nowStarTime(){
        //获取当前年月
        String nowYm = getNow(FORMAT_YM);
        //当前年
        int nowY = Integer.parseInt(nowYm.split("-")[0]);
        //当前月
        int nowM = Integer.parseInt(nowYm.split("-")[1]);
        //本月开始时间
        String nowStarTime = getBeginTime(nowY,nowM);
        return nowStarTime;
    }
    /**
     * 本月结束时间
     * @return
     */
    public static String nowEndTime(){
        //获取当前年月
        String nowYm = getNow(FORMAT_YM);
        //当前年
        int nowY = Integer.parseInt(nowYm.split("-")[0]);
        //当前月
        int nowM = Integer.parseInt(nowYm.split("-")[1]);
        //本月开始时间
        String nowEndTime = getEndTime(nowY,nowM);
        return nowEndTime;
    }

    /**
     * String时间转换成Long类型
     * @param date
     * @return
     */
    public static Long strToLong(String date){
        SimpleDateFormat format = new SimpleDateFormat(YMD);
        long newDate = 0l;
        try {
            Date dateStart = format.parse(date);
            newDate = (long) (dateStart.getTime() / 1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newDate;
    }
    /**
     * 时间戳转日期
     * @param timeStr
     * @param pattern
     * @return
     */
    public static String getDate(long timeStr, String pattern){
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        Date date = new Date(timeStr);
        return df.format(date);
    }

    /**
     * 获取当前时间对应的年月日0点的时间戳
     * @param time
     * @return
     */
    public static long getCurrentYMDTime(long time){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date(time);
        String dateKey = simpleDateFormat.format(date);
        try {
            return simpleDateFormat.parse(dateKey).getTime();
        } catch (ParseException e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 按用户格式字符串距离今天的天数
     * @param date 日期字符串
     * @param format 日期格式
     * @return
     */
    public static int countDays(String date, String format) {
        long t = Calendar.getInstance().getTime().getTime();
        Calendar c = Calendar.getInstance();
        c.setTime(parse(date, format));
        long t1 = c.getTime().getTime();
        return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
    }

    /**
     * 获取服务器启动时间
     * @return Date
     */
    public static Date getServerStartDate(){
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }
    /**
     * localDateTime转成Long
     * @param localDateTime
     * @return
     */
    public static Long localDateTimetoLong(LocalDateTime localDateTime){
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * @Description: 获得本周一与当前日期相差的天数
     * @Param: [times, timeUnit]
     * @return: java.util.Date
     * @Author: songLei
     * @Date: 2019/11/28 17:52
     */
    public static  int getMondayPlus() {
        Calendar cd = Calendar.getInstance();
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {
            return -6;
        } else {
            return 2 - dayOfWeek;
        }
    }
    /**
     * @Description: 获得当前周- 周一的日期
     * @Param: [times, timeUnit]
     * @return: java.util.Date
     * @Author: songLei
     * @Date: 2019/11/28 17:52
     */
    public static  String getCurrentMonday() {
        LocalDate today = LocalDate.now();
        LocalDate monday = today.with(TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY));
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String stringLocalTime = df.format(monday);
        return stringLocalTime;
    }

    /**
     * @Description: 获得当前周- 周日  的日期
     * @Param: [times, timeUnit]
     * @return: java.util.Date
     * @Author: songLei
     * @Date: 2019/11/28 17:52
     */
    public static String getPreviousSunday() {
        LocalDate today = LocalDate.now();
        LocalDate sunday = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String stringLocalTime = df.format(sunday);
        return stringLocalTime;
    }

    /**
     * @Description: 输入日期获得星期
     * @Param: [times, timeUnit]
     * @return: java.util.Date
     * @Author: songLei
     * @Date: 2019/11/28 17:52
     */
    public static Integer dayForWeek(String pTime){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        Integer[] weekDays = { 7, 1, 2, 3, 4, 5, 6};
        try {
            Date tmpDate = format.parse(pTime);
            cal.setTime(tmpDate);
        } catch (Exception e) {
            e.printStackTrace();
        }
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (w < 0)
            w = 0;
        return weekDays[w];
    }
    /**
     * @Description: LocalDateTime转String
     * @param time
     * @return: localTime
     * @Author: 瑾年
     * @Date: 2019/11/28 17:52
     */
    public static String localDateTimeToString(LocalDateTime time){
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMAT_LONG);
        String localTime = df.format(time);
        return localTime;
    }
}
